// ----------------------------------------------------------------------------
// Copyright 2006, Martin D. Flynn
// All rights reserved
// ----------------------------------------------------------------------------
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ----------------------------------------------------------------------------
// Description:
//  Container for GPS events.
// ----------------------------------------------------------------------------
// Change History:
//  2006/03/26  Martin D. Flynn
//      Initial release
// ----------------------------------------------------------------------------
package org.traffometer.opendmtp.protocol;


/**
 * Provides an container for GPS events. keeping track of a piece of GPS information in sequence of
 * events of each entity.
 * 
 * @author Martin D. Flynn
 * @author Yoshiaki Iinuma
 */
public class GeoEvent {

  // ------------------------------------------------------------------------

  /**
   * Represents the value of the minimum specific GPS/Transit data recommended in NMEA 0183
   * standard.
   */
  public static final long NMEA0183_GPRMC = 0x00000001L;
  /** 
   * Represents the value of global positioning system fix data recommended in NMEA 0183 standard.
   */
  public static final long NMEA0183_GPGGA = 0x00000002L;

  // ------------------------------------------------------------------------

  private int gpsStatusCode = 0;
  private long gpsTimestamp1 = 0L;
  private long gpsTimestamp2 = 0L;
  private long gpsIndex = 0L;
  private double gpsLatitude1 = 0.0;
  private double gpsLatitude2 = 0.0;
  private double gpsLongitude1 = 0.0;
  private double gpsLongitude2 = 0.0; 
  private double gpsSpeedKPH = 0.0;
  private double gpsHeading = 0.0;
  private double gpsAltitude = 0.0;
  private double gpsDistanceKM = 0.0;
  private double gpsHDOP = 0.0;
  private long gpsSequence = 0L;
  private String vehicle = "unknown";

  /**
   * Default constructor of GeoEvent.
   * 
   */
  public GeoEvent() { // NOPMD
    // do nothing
  }

  // ------------------------------------------------------------------------

  /** 
   * Returns the status code of this GPS event.
   * 
   * @return the status code of this GPS event.
   */
  public int getStatusCode() {
    return this.gpsStatusCode;
  }

  /**
   * Sets the specified value to the status code of this GPS event.
   * 
   * @param code the code value to be set.
   */
  public void setStatusCode(int code) {
    this.gpsStatusCode = code;
  }

  // ------------------------------------------------------------------------

  /**
   * Returns the value of the first timestamp of this GPS event.
   * 
   * @return the value of the timestamp of this GPS event.
   */
  public long getTimestamp1() {
    return this.gpsTimestamp1;
  }

  /**
   * Returns the value of the second timestamp of this GPS event.
   * 
   * @return the value of the timestamp of this GPS event.
   */
  public long getTimestamp2() {
    return this.gpsTimestamp2;
  }
  
  /**
   * Sets the specified time to the first timestamp of this GPS event.
   * 
   * @param time the timestamp value to be set.
   */
  public void setTimestamp1(long time) {
    this.gpsTimestamp1 = time;
  }

  /**
   * Sets the specified time to the first timestamp of this GPS event.
   * 
   * @param time the timestamp value to be set.
   */
  public void setTimestamp2(long time) {
    this.gpsTimestamp2 = time;
  }

  // ------------------------------------------------------------------------

  /**
   * Returns the value of the index of this GPS event.
   * 
   * @return the value of the index of this GPS event.
   */
  public long getIndex() {
    return this.gpsIndex;
  }

  /**
   * Sets the specified value of the index of this GPS event.
   * 
   * @param ndx the index value to be set.
   */
  public void setIndex(long ndx) {
    this.gpsIndex = ndx;
  }

  // ------------------------------------------------------------------------

  /**
   * Returns the value of the first point's latitude of this GPS event.
   * 
   * @return the value of the latitude of this GPS event.
   */
  public double getLatitude1() {
    return this.gpsLatitude1;
  }

  /**
   * Returns the value of the second point's latitude of this GPS event.
   * 
   * @return the value of the latitude of this GPS event.
   */
  public double getLatitude2() {
    return this.gpsLatitude2;
  }
  
  /**
   * Sets the specified value of the first point's latitude of this GPS event.
   * 
   * @param lat the value of latitude to be set.
   */
  public void setLatitude1(double lat) {
    this.gpsLatitude1 = lat;
  }

  /**
   * Sets the specified value of the second point's latitude of this GPS event.
   * 
   * @param lat the value of latitude to be set.
   */
  public void setLatitude2(double lat) {
    this.gpsLatitude2 = lat;
  }

  /**
   * Returns the value of the first point's longitude of this GPS event.
   * 
   * @return the value of the longitude of this GPS event.
   */
  public double getLongitude1() {
    return this.gpsLongitude1;
  }
  
  /**
   * Sets a vehicle type.
   * 
   * @param vehicleType String containing vehicle type.
   */
  public void setVehicle(String vehicleType) {
    this.vehicle = vehicleType;
  }
  
  /**
   * Returns a vehicle type.
   * 
   * @return String vehicle type.
   */
  public String getVehicle() {
    return this.vehicle ;
  }

  /**
   * Returns the value of the second point's longitude of this GPS event.
   * 
   * @return the value of the longitude of this GPS event.
   */
  public double getLongitude2() {
    return this.gpsLongitude2;
  }

  /**
   * Sets the specified value of the first point's longitude of this GPS event.
   * 
   * @param lon the value of longitude to be set.
   */
  public void setLongitude1(double lon) {
    this.gpsLongitude1 = lon;
  }

  
  /**
   * Sets the specified value of the first point's longitude of this GPS event.
   * 
   * @param lon the value of longitude to be set.
   */
  public void setLongitude2(double lon) {
    this.gpsLongitude2 = lon;
  }
  
  /**
   * Return the GeoPoint object containing the information about the position and the time of this
   * GPS event.
   * 
   * @return the GeoPoint object containing the information about the position and the time of this
   *         GPS event.
   */
  public GeoPoint getGeoPoint1() {
    return new GeoPoint(this.getLatitude1(),this.getLongitude1(),this.getTimestamp1());
  }
  /**
   * Return the GeoPoint object containing the information about the position and the time of this
   * GPS event.
   * 
   * @return the GeoPoint object containing the information about the position and the time of this
   *         GPS event.
   */
  public GeoPoint getGeoPoint2() {
    return new GeoPoint(this.getLatitude2(),this.getLongitude2(),this.getTimestamp2());
  }

  
  
  /**
   * Tests if this GPS event has a valid position value.
   * 
   * @return true if this GPS event has a valid position value.
   */
  public boolean isValid() {
    double lat1 = this.getLatitude1();
    double lon1 = this.getLongitude1();
    double lat2 = this.getLatitude2();
    double lon2 = this.getLongitude2();
    boolean validTime = ((this.getTimestamp1() >= 0) && (this.getTimestamp2() >= 0));
    return (validTime) && ((lat1 != 0.0) || (lon1 != 0.0)) && ( (lat2 != 0.0) || (lon2 != 0.0));
  }

  // ------------------------------------------------------------------------

  /**
   * Returns the value of the speed of this GPS event in KPH.
   * 
   * @return the value of the speed of this GPS event in KPH.
   */
  public double getSpeedKPH() {
    return this.gpsSpeedKPH;
  }

  /**
   * Returns the value of the speed of this GPS event in MPH.
   * 
   * @return the value of the speed of this GPS event in MPH.
   */
  public double getSpeedMPH() {
    return this.gpsSpeedKPH * GeoPoint.MILES_PER_KILOMETER;
  }

  /**
   * Sets the specified value to the speed of this GPS event in KPH.
   * 
   * @param kph the speed to be set.
   */
  public void setSpeedKPH(double kph) {
    this.gpsSpeedKPH = kph;
  }

  /**
   * Resets the speed and the heading of this GPS event to zero unless it gets to the specified
   * minimum speed.
   * 
   * @param minSpeedKPH the minimum speed to which the speed of this GPS event is required to reach.
   */
//  public void checkMinimumSpeed(double minSpeedKPH) {
//    if (this.getSpeedKPH() < minSpeedKPH) {
//      // the reported speed does not meet the minimum requirement
//      // mark the speed as 'not moving'
//      this.setSpeedKPH(0.0);
//      this.setHeading(0.0);
//    }
//  }

  // ------------------------------------------------------------------------

  /**
   * Returns the value of the direction of this GPS event.
   * 
   * @return the value of the direction of this GPS event.
   */
  public double getHeading() {
    return this.gpsHeading;
  }

  /**
   * Sets the specified value to the direction of this GPS event.
   * 
   * @param deg the value of the direction to be set.
   */
  public void setHeading(double deg) {
    this.gpsHeading = deg;
  }

  // ------------------------------------------------------------------------

  /**
   * Returns the value of the altitude of this GPS event in meter.
   * 
   * @return the value of the altitude of this GPS event in meter.
   */
  public double getAltitude() {
    return this.gpsAltitude; // meters
  }

  /**
   * Returns the value of the altitude of this GPS event in feet.
   * 
   * @return the value of the altitude of this GPS event in feet.
   */
//  public double getAltitudeFeet() {
//    return this.gpsAltitude * GeoPoint.FEET_PER_METER; // feet
//  }

  /**
   * Sets the specified value to the altitude of this GPS event in meter.
   * 
   * @param meters the value of the altitude to be set.
   */
  public void setAltitude(double meters) {
    this.gpsAltitude = meters;
  }

  // ------------------------------------------------------------------------

  /**
   * Returns the value of the distance of this GPS event in km.
   * 
   * @return the value of the distance of this GPS event in km.
   */
  public double getDistanceKM() {
    return this.gpsDistanceKM;
  }

  /**
   * Sets the specified value to the distance of this GPS event in km.
   * 
   * @param km the value of the distance to be set in km.
   */
  public void setDistanceKM(double km) {
    this.gpsDistanceKM = km;
  }

  // ------------------------------------------------------------------------

  /**
   * Return the value of the horizontal dilution of precision of this GPS event.
   * 
   * @return the value of the horizontal dilution of precision of this GPS event.
   */
  public double getHDOP() {
    return this.gpsHDOP;
  }

  /**
   * Sets the value to the horizontal dilution of precision of this GPS event.
   * 
   * @param hdop the value of the horizontal dilution of precision to be set.
   */
  public void setHDOP(double hdop) {
    this.gpsHDOP = hdop;
  }

  // ------------------------------------------------------------------------

  /**
   * Return the value of the sequence of this GPS event.
   * 
   * @return the value of the sequence of this GPS event.
   */
  public long getSequence() {
    return this.gpsSequence;
  }

  /**
   * Sets the value to the sequence of this GPS event.
   * 
   * @param seq the value of the sequence to be set.
   */
  public void setSequence(long seq) {
    this.gpsSequence = seq;
  }

  // ------------------------------------------------------------------------

  /**
   * Copy the contents of this GPS event to the other.
   * 
   * @param gev the GeoEvent object to which the contents of this GPS event are copied.
   * @return the GeoEvent object to which the contents of this GPS event are copied. If the passed
   *         GeoEvent is null, a new instance is created.
   */
//  public GeoEvent copyTo(GeoEvent gev) {
//    if (gev == null) {
//      gev = new GeoEvent();
//    }
//    gev.setStatusCode(this.getStatusCode());
//    gev.setTimestamp1(this.getTimestamp1());
//    gev.setTimestamp2(this.getTimestamp2());
//    gev.setIndex(this.getIndex());
//    gev.setLatitude1(this.getLatitude1());
//    gev.setLatitude2(this.getLatitude2());
//    gev.setLongitude1(this.getLongitude1());
//    gev.setLongitude2(this.getLongitude2());
//    gev.setSpeedKPH(this.getSpeedKPH());
//    gev.setHeading(this.getHeading());
//    gev.setAltitude(this.getAltitude());
//    gev.setDistanceKM(this.getDistanceKM());
//    gev.setHDOP(this.getHDOP());
//    gev.setSequence(this.getSequence());
//    return gev;
//  }

  // ------------------------------------------------------------------------

}
